from datetime import datetime
from typing import Union
from urllib.parse import parse_qs
from user_agents import parse
from afast_core.core_libs.logger.v1 import init_logging
from pydantic import BaseSettings as Settings
from fastapi import FastAPI
from .enums import RecordModel
from .middleware import LoguruPluginClientMiddleware
from ..pluginbase import IBasePlugin as BasePlugin

from starlette.requests import Request


class LoguruPluginClient(BasePlugin):
    '''
    注意事项：
    因为是日志作用，所以一般使用的时候最后再执行注册
    ------------------
    用法示例：
    log = LoguruPluginClient(core_app=core_app,configs=LoguruPluginClient.LoguruConfig(
     MODEL = RecordModel.CENTRALIZED
    ))
    from afast_core.core_plugins.log import logger
    @core_app.get("/stream12")
    def stream():
        # 写入
        # print("dddddddddf",logrequest.state.background)
        # infirmary_tasks = BackgroundTask(logger.info, 'aaaaa22222222222222---1')
        # logrequest.state.background = infirmary_tasks
        # infirmary_tasks.add_task(logger.info,'aaaaa22222222222222---1')
        # log.bind(ip=get_client_ip(request)).info('aaaaa')
        logger.info('日志记录信息')
        # 读取（另一个接口读取）
        # cyrewct_code = request.session["session_code"]
        return {
            "dasd":2323
        }
    '''

    name = '日志记录插件'

    # 再静态的里面使用self来查询也可以，遵循从内到外的查询

    def filter_request_url(self, request: Request):
        path_info = request.url.path
        # print("当前地址：",path_info)
        # print(self.configs.FLITER_REQUEST_URL )
        # print('aaaaaaaaaaaa',path_info in self.configs.FLITER_REQUEST_URL)
        # print('过滤不需要记录日志请求地址URL', path_info in self.configs.FLITER_REQUEST_URL or 'websocket' in path_info or request.method != 'OPTIONS')
        # 过滤不需要记录日志请求地址URL
        if request.method == 'OPTIONS':
            return True
        if 'websocket' in path_info:
            return True
        return path_info in self.settings.FLITER_REQUEST_URL

    class LoguruConfig(Settings):

        # =========================记录模式
        MODEL = RecordModel.CENTRALIZED

        # =========================
        # 配置日志相关信息
        PROJECT_SLUG: str = "info"
        # 日志文件的目录,当前插件初始化位置所在的目录
        LOG_FILE_PATH: str = "."
        # 日志文件切割的日期- rotation='00:00',  # 每天 0 点创建一个新日志文件
        LOG_FILE_ROTATION: str = "00:00"
        # 日志文件的保留的天数  #  retention="7 days",  # 定时自动清理文件
        LOG_FILE_RETENTION: Union[int, str] = 8
        # 日志压缩的搁置
        LOG_FILE_COMPRESSION: str = "gz"
        # 日志记录的等等级
        LOG_FILE_LEVEL: str = "INFO"
        # =========================
        # 日志记录相关配置-
        NESS_ACCESS_HEADS_KEYS = []
        # 是否记录响应报文内容，如果包含内容过多，不建议记录
        IS_RECORD_RESPONSE: bool = True
        # 是否记录用户提交请求头信息
        IS_RECORD_HEADERS: bool = True
        # 是否记录用户UA信息
        IS_RECORD_UA: bool = True
        # 需要过来的请求URL路径信息
        FLITER_REQUEST_URL = ['/favicon.ico', '/docs', '/', '/openapi.json','/health_checks']

    async def make_request_log_msg(self, request: Request):
        log_msg = None
        if self.filter_request_url(request):
            request.state.close_record = True
        else:
            ip, method, url = request.client.host, request.method, request.url.path
            # 解析请求提交的表单信息
            try:
                body_form = await request.form()
            except:
                body_form = None

            # 解析请求提交的body信息
            body = None
            try:
                pass
                body_bytes = await request.body()
                if body_bytes:
                    try:
                        body = await  request.json()
                    except:
                        pass
                        if body_bytes:
                            try:
                                body = body_bytes.decode('utf-8')
                            except:
                                body = body_bytes.decode('gb2312')
            except Exception as e:
                raise e
            # 在这里记录下当前提交的body的数据，用于下文的提取
            request.state.body = body
            # 从头部里面获取出对应的请求头信息，用户用户机型等信息获取
            try:
                user_agent = parse(request.headers["user-agent"])
                browser = user_agent.browser.version
                if len(browser) >= 2:
                    browser_major, browser_minor = browser[0], browser[1]
                else:
                    browser_major, browser_minor = 0, 0
                # 用户当前系统OS信息提取
                user_os = user_agent.os.version
                if len(user_os) >= 2:
                    os_major, os_minor = user_os[0], user_os[1]
                else:
                    os_major, os_minor = 0, 0

                log_msg = {
                    # 'headers': str(gziprequest.headers),
                    # 'user_agent': str(gziprequest.user_agent),
                    # 记录请求头信息----如果需要特殊的获取某些请求的记录则做相关的配置即可
                    'headers': None if not self.settings.IS_RECORD_HEADERS else
                    [request.headers.get(i, '') for i in
                     self.settings.NESS_ACCESS_HEADS_KEYS] if self.settings.NESS_ACCESS_HEADS_KEYS else None,
                    # 记录请求URL信息
                    "useragent": None if not self.settings.IS_RECORD_UA else
                    {
                        "os": "{} {}".format(user_agent.os.family, user_agent.os.version_string),
                        'browser': "{} {}".format(user_agent.browser.family, user_agent.browser.version_string),
                        "device": {
                            "family": user_agent.device.family,
                            "brand": user_agent.device.brand,
                            "model": user_agent.device.model,
                        }
                    },
                    'url': url,
                    # 记录请求方法
                    'method': method,
                    # 记录请求来源IP
                    # 'ip': ip,
                    # 'path': gziprequest.path,
                    # 记录请求提交的参数信息
                    'params': {
                        'query_params': parse_qs(str(request.query_params)),
                        'from': body_form,
                        'body': body
                    },
                    # 记录请求的开始时间
                    "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}'
                    # 'start_time':  f'{(start_time)}',
                }
            except Exception as e:
                log_msg = {
                    # 'headers': str(gziprequest.headers),
                    # 'user_agent': str(gziprequest.user_agent),
                    # 记录请求头信息----如果需要特殊的获取某些请求的记录则做相关的配置即可
                    'headers': None if not self.settings.IS_RECORD_HEADERS else
                    [request.headers.get(i, '') for i in
                     self.settings.NESS_ACCESS_HEADS_KEYS] if self.settings.NESS_ACCESS_HEADS_KEYS else None,
                    'url': url,
                    # 记录请求方法
                    'method': method,
                    # 记录请求来源IP
                    # 'ip': ip,
                    # 'path': gziprequest.path,
                    # 记录请求提交的参数信息
                    'params': {
                        'query_params': parse_qs(str(request.query_params)),
                        'from': body_form,
                        'body': body
                    },
                    # 记录请求的开始时间
                    "ts": f'{datetime.now():%Y-%m-%d %H:%M:%S%z}'
                    # 'start_time':  f'{(start_time)}',
                }
                raise e

            # 对于没有的数据清除
            if not log_msg['headers']:
                log_msg.pop('headers')
            if not log_msg['params']['query_params']:
                log_msg['params'].pop('query_params')
            if not log_msg['params']['from']:
                log_msg['params'].pop('from')
            if not log_msg['params']['body']:
                log_msg['params'].pop('body')
        return log_msg

    def setup(self, app: FastAPI, name: str = None, settings=None, *args, **kwargs):
        """插件初始化"""

        # init_logging_ex = init_logging(app_config)
        # def init_logging_ex():
            # return init_logging(settings)

        # 开始初始化
        # core_app.add_event_handler("startup", init_logging_ex)
        init_logging(settings)
        app.add_middleware(LoguruPluginClientMiddleware, is_proxy=True, client=self)

        # 为了获取到日志的链路追踪ID信息和IP等信息，需要做一个全局的请求---PS:不用基于下面这个，否贼在Post设计重复消费问题，引发阻塞
        # @core_app.core_middleware("http")
        # async def core_middleware(request: Request, call_next):
        #     # 解析当前的请求体
        #     token = log_request_var.set(request)
        #     # # 追踪ID
        #     request.state.traceid = str(shortuuid.uuid())
        #     request.state.traceindex = 0
        #     #
        #     request.state.close_record = False
        #     # # 计算时间
        #     request.state.start_time = perf_counter()
        #     #
        #     # 离散是日志记录模式
        #     if self.configs.MODEL == RecordModel.SCATTERED:
        #         logrequest.state.record_model = RecordModel.SCATTERED
        #         log_msg = await self.make_request_log_msg(request)
        #         # 如果过滤了，则也记录请求信息了
        #         if log_msg:
        #             logger.info(log_msg, event_name='request')
        #     else:
        #         # 集中式日志记录模式已
        #         pass
        #         # 创建全局是日志上下文
        #         logrequest.state.record_model = RecordModel.CENTRALIZED
        #         request.state.trace_logs_record = []
        #         log_msg = await self.make_request_log_msg(request)
        #         logger.info(log_msg, event_name='request', )
        #
        #     try:
        #         response = await call_next(request)
        #
        #         response_body = b''
        #         # 解析读取对应的响应报文内容型芯
        #         async for chunk in response.body_iterator:
        #             response_body += chunk
        #         # 生成最终响应报文内容
        #         response = Response(
        #             content=response_body,
        #             status_code=response.status_code,
        #             headers=dict(response.headers),
        #             media_type=response.media_type
        #         )
        #         # 记录响应报文体内容信息，
        #         # if self.configs.IS_RECORD_RESPONSE and log_msg and response.status_code != 404:
        #         #     logger.info(str(response_body, 'utf-8'), event_name='response')
        #         return response
        #     except Exception as ex:
        #         # 解析响应报文的body异常信息
        #         response_body = bytes(http.HTTPStatus.INTERNAL_SERVER_ERROR.phrase.encode())
        #         response = Response(
        #             content=response_body,
        #             status_code=http.HTTPStatus.INTERNAL_SERVER_ERROR.real,
        #         )
        #         # 记录响应报文体内容信息，
        #
        #         # logger.info(str(response_body, 'utf-8'),event_name='exception response')
        #         return response
        #         # raise ex
        #     finally:
        #         request.state.traceindex = None
        #         request.state.traceid = None
        #         request.state.trace_logs_record = None
        #         log_request_var.reset(token)
